﻿using Magicodes.ExporterAndImporter.Core.Models;
using Magicodes.ExporterAndImporter.Excel;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data.Common;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

namespace PHMEE.ToolKits
{
    public static class PHMEECoreHelper
    {

        #region 枚举

        public static string PhmeeGetValue(Enum value)
        {
            return value.ToString();
        }

        public static string PhmeeGetDescription(Enum value)
        {
            var field = value.GetType().GetField(value.ToString());

            if (field == null) return null;

            var attribute = (DescriptionAttribute)Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute));

            return attribute?.Description;
        }

        public static Enum GetEnumByDescription(string description, Type enumType)
        {
            foreach (var value in Enum.GetValues(enumType))
            {
                var field = enumType.GetField(value.ToString());
                var attribute = (DescriptionAttribute)Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute));

                if (attribute?.Description == description)
                {
                    return (Enum)value;
                }
            }

            return null; // 没有匹配项返回 null
        }



        public static Dictionary<int, object> PhmeeGetEnumKeyDescriptions<TEnum>(IEnumerable<TEnum> filter = null) where TEnum : Enum
        {
            var enumKeyValues = new Dictionary<int, object>();

            foreach (var value in Enum.GetValues(typeof(TEnum)))
            {
                if (filter == null || filter.Contains((TEnum)value))
                {
                    var key = (int)value;
                    var description = PhmeeGetDescription((Enum)value);

                    enumKeyValues.Add(key, description);
                }
            }

            return enumKeyValues;
        }

        public static List<TEnum> PhmeeGetEnumsFilter<TEnum>(int lowerBound = 0, int upperBound = int.MaxValue) where TEnum : Enum
        {
            return Enum.GetValues(typeof(TEnum)).Cast<TEnum>().Where(e => (int)(object)e >= lowerBound && (int)(object)e <= upperBound).ToList();
        }

        public static Dictionary<string, int> PhmeeGetEnumKeyValues<TEnum>() where TEnum : Enum
        {
            var enumKeyValues = new Dictionary<string, int>();

            foreach (var value in Enum.GetValues(typeof(TEnum)))
            {
                var key = value.ToString();
                var intValue = (int)value;

                enumKeyValues.Add(key, intValue);
            }

            return enumKeyValues;
        }

        public static List<string> PhmeeGetEnumNames<TEnum>() where TEnum : Enum
        {
            return new List<string>(Enum.GetNames(typeof(TEnum)));
        }

        public static List<int> PhmeeGetEnumValues<TEnum>() where TEnum : Enum
        {
            return new List<int>(Enum.GetValues(typeof(TEnum)) as int[]);
        }

        public static bool PhmeeIsEnumValueDefined<TEnum>(int value) where TEnum : Enum
        {
            return Enum.IsDefined(typeof(TEnum), value);
        }

        #endregion

        #region 反射


        public static Dictionary<string, object> GetDerivedProperties(object obj, bool includeAll = false)
        {
            Dictionary<string, object> dict = new Dictionary<string, object>();

            Type objectType = obj.GetType();

            foreach (var property in objectType.GetProperties())
            {
                if (includeAll)
                {
                    if (property != null)
                    {
                        dict.Add(property.Name, property.GetValue(obj));
                    }
                }
                else
                {
                    if (property != null && property.DeclaringType == objectType)
                    {
                        dict.Add(property.Name, property.GetValue(obj));
                    }
                }

            }

            return dict;
        }

        public static void SetDerivedProperties(object obj, Dictionary<string, object> properties)
        {
            Type objectType = obj.GetType();

            foreach (var pair in properties)
            {
                PropertyInfo property = objectType.GetProperty(pair.Key);

                if (property != null && property.DeclaringType == objectType)
                {
                    object value = pair.Value;

                    var valuetype = value.GetType();

                    Type propertyType = property.PropertyType;

                    if (propertyType == typeof(int) && value is long)
                    {
                        value = Convert.ToInt32(value);
                    }
                    else if (propertyType.IsEnum && value is long)
                    {
                        value = Convert.ToInt32(value);
                    }
                    else if (propertyType == typeof(float) && value is double)
                    {
                        value = Convert.ToSingle(value);
                    }
                    else if (propertyType == typeof(double) && value is double)
                    {
                        value = Convert.ToDouble(value);
                    }
                    else if (propertyType == typeof(decimal) && value is double)
                    {
                        value = Convert.ToDecimal(value);
                    }

                    // 设置属性值
                    property.SetValue(obj, value);
                }
            }
        }

        public static void ClearDerivedProperties(object obj)
        {
            Type objectType = obj.GetType();

            foreach (var property in objectType.GetProperties())
            {
                if (property != null && property.DeclaringType == objectType)
                {
                    // 清空属性值
                    property.SetValue(obj, null);
                }
            }
        }

        #endregion

        #region 日期时间

        /// <summary>
        /// 获取指定日期的当天 UTC 的起始时间（0点）。
        /// </summary>
        /// <param name="date">传入的 UTC 时间</param>
        /// <returns>当天 UTC 时间的 0 点</returns>
        public static DateTime PhmeeToStartOfDayUtc(this DateTime date)
        {
            return new DateTime(date.Year, date.Month, date.Day, 0, 0, 0, DateTimeKind.Utc);
        }

        public static string PhmeeToFriendlyDateString(this DateTime date)
        {
            return date.ToString("yyyy-MM-dd");
        }


        public static string PhmeeToFriendlyTimeString(this DateTime date)
        {
            return date.ToString("HH:mm:ss");
        }

        public static string PhmeeToFriendlyDateTimeString(this DateTime date)
        {
            return date.ToString("yyyy-MM-dd HH:mm:ss");
        }

        /// <summary>
        /// 转换为类似格式：03 Dec 2024, 14:00 时间展示
        /// </summary>
        /// <param name="date"></param>
        /// <returns></returns>
        public static string PhmeeToFriendlyDateTimeSpecialString(this DateTime date)
        {
            return date.ToString("dd MMM yyyy, HH:mm", CultureInfo.InvariantCulture);
        }

        /// <summary>
        /// 转为 UTC 格式的时间，但年、月、日、时、分、秒、毫秒的值均不变
        /// </summary>
        /// <param name="date"></param>
        /// <returns></returns>
        public static string PhmeeToUtcFormatDateTimeString(this DateTime date)
        {
            return date.ToString("yyyy-MM-ddTHH:mm:ss.fffZ");
        }

        #endregion

        #region 序列化

        public static string Serialize<T>(T obj)
        {
            return JsonSerializer.Serialize(obj);
        }

        public static T Deserialize<T>(string json)
        {
            return JsonSerializer.Deserialize<T>(json);
        }

        #endregion

        #region TdEngine

        public static T GetPhmeeTdEngineValue<T>(this DbDataReader reader, string columnName)
        {
            int ordinal = reader.GetOrdinal(columnName);
            T value = reader.IsDBNull(ordinal) ? default(T) : reader.GetFieldValue<T>(ordinal);

            if (value is DateTime dateTime)
            {
                return (T)(object)dateTime.ToUniversalTime();
            }

            return reader.IsDBNull(ordinal) ? default(T) : reader.GetFieldValue<T>(ordinal);
        }

        #endregion

        #region 文件导入

        public static async Task<Tuple<ImportResult<T>, string>> ImportPhmeeExcelFile<T>(this IExcelImporter excelImporter, byte[] bytes, string fileName) where T : class, new()
        {
            var fileExtension = Path.GetExtension(fileName).ToLower();

            if (fileExtension != ".xlsx")
            {
                return Tuple.Create<ImportResult<T>, string>(null, "只能导入xlsx类型的Excel文件");
            }

            string errors = string.Empty;

            var result = await excelImporter.Import<T>(new MemoryStream(bytes));

            if (result.HasError)
            {
                StringBuilder sb = new StringBuilder();

                if (result.RowErrors.Count > 0)
                {
                    sb.Append(string.Join(Environment.NewLine, result.RowErrors.Select(rowError =>
                    {
                        var fieldErrors = string.Join(", ", rowError.FieldErrors.Select(fe => $"{fe.Key}:{fe.Value}"));
                        return $"第{rowError.RowIndex}行{fieldErrors}";
                    })));
                }
                if (result.TemplateErrors.Count > 0)
                {
                    sb.Append(string.Join(Environment.NewLine, result.TemplateErrors.Select(rowError =>
                    {
                        var templateErrors = $"{rowError.Message}{rowError.RequireColumnName}";
                        return $"{templateErrors}";
                    })));
                }

                errors = sb.ToString();
            }

            return Tuple.Create(result, errors);
        }

        #endregion

        #region GPS经纬度

        /// <summary>
        /// 度分格式 例如：122°06.786 E
        /// </summary>
        /// <param name="coordinate"></param>
        /// <param name="direction"></param>
        /// <returns></returns>
        public static string ToDMS(this float coordinate, string direction)
        {

            var degrees = Math.Floor(coordinate);

            var minutesDecimal = (coordinate - degrees) * 60;

            return $"{degrees}°{minutesDecimal:00.000} {direction}";

        }

        /// <summary>
        /// 经度
        /// </summary>
        /// <param name="longitude"></param>
        /// <returns></returns>
        public static string LongitudeToDMS(this float longitude)
        {

            var direction = longitude >= 0 ? "E" : "W";

            return Math.Abs(longitude).ToDMS(direction);

        }

        /// <summary>
        /// 维度
        /// </summary>
        /// <param name="latitude"></param>
        /// <returns></returns>
        public static string LatitudeToDMS(this float latitude)
        {

            var direction = latitude >= 0 ? "N" : "S";

            return Math.Abs(latitude).ToDMS(direction);

        }

        #endregion
    }
}
